/**
 * 
 */
package com.common.distributed.algorithm.redis.mapping.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

import com.common.distributed.algorithm.blance.IBlanceDistributedAlgorithm;
import com.common.distributed.algorithm.blance.impl.BlanceDistributedAlgorithmImpl;
import com.common.distributed.algorithm.model.AlgorithmModel;
import com.common.distributed.algorithm.redis.mapping.ISearchDistributedIndex;

/**
 * @author liubing
 * 
 */
public class SearchDistributedIndexImpl implements ISearchDistributedIndex {
	
	private final static Log log = LogFactory.getLog(SearchDistributedIndexImpl.class);
	
	private IBlanceDistributedAlgorithm blanceDistributedAlgorithm;

	private ShardedJedisPool shardedJedisPool;
	
	private ShardedJedisPool readShardedJedisPool;
	
	private Map<String, AlgorithmModel> maps=new HashMap<String, AlgorithmModel>();
	
	public SearchDistributedIndexImpl(List<AlgorithmModel> algorithmModels){
		blanceDistributedAlgorithm=new BlanceDistributedAlgorithmImpl(algorithmModels);
		for(AlgorithmModel algorithmModel:algorithmModels){
			maps.put(algorithmModel.getName(), algorithmModel);
		}
	}
	
	/* (non-Javadoc)
	 * @see com.jd.distributed.algorithm.redis.mapping.ISearchDistributedIndex#getResultByKey(java.lang.String)
	 */
	public AlgorithmModel getResultByKey(String key) {
		// TODO Auto-generated method stub
		ShardedJedis shardedJedis=shardedJedisPool.getResource();
		String result=null;
		try{
			if(shardedJedis.exists(key)){
				result= shardedJedis.get(key);
			}else{
				result=blanceDistributedAlgorithm.getAlgorithmModel().getName();
				saveMappingData(key, result);
			}
		}catch(Exception e){
			log.error("getResultByKey fail shardedJedisPool,this reason",e);
			shardedJedisPool.returnBrokenResource(shardedJedis);
			if(readShardedJedisPool!=null){
				ShardedJedis readShardedJedis=readShardedJedisPool.getResource();
				try{
					result= readShardedJedis.get(key);
					readShardedJedisPool.returnResource(readShardedJedis);
				}catch(Exception ex){
					log.error("getResultByKey fail by readShardedJedisPool ,this reason",e);
					readShardedJedisPool.returnBrokenResource(readShardedJedis);
				}
			}
			
		}
		shardedJedisPool.returnResource(shardedJedis);
		return maps.get(result);
	}

	/* (non-Javadoc)
	 * @see com.jd.distributed.algorithm.redis.mapping.ISearchDistributedIndex#saveMappingData(java.lang.String, java.lang.String)
	 */
	public boolean saveMappingData(String key, String result) {
		// TODO Auto-generated method stub
		ShardedJedis shardedJedis=shardedJedisPool.getResource();
		try{
			shardedJedis.set(key, result);
			shardedJedis.rpush(result, key);
			shardedJedisPool.returnResource(shardedJedis);
		}catch(Exception e){
			log.error("saveMappingData fail by shardedJedisPool,this reason",e);
			shardedJedisPool.returnBrokenResource(shardedJedis);
			if(readShardedJedisPool!=null){
				ShardedJedis readShardedJedis=readShardedJedisPool.getResource();
				try{
					readShardedJedis.set(key, result);
					readShardedJedis.rpush(result, key);
					readShardedJedisPool.returnResource(readShardedJedis);
				}catch(Exception ex){
					log.error("saveMappingData fail by readShardedJedisPool ,this reason",e);
					readShardedJedisPool.returnBrokenResource(readShardedJedis);
				}
			}
			
			return false;
		}
		return true;
	}

	public void setShardedJedisPool(ShardedJedisPool shardedJedisPool) {
		this.shardedJedisPool = shardedJedisPool;
	}

	@Override
	public List<AlgorithmModel> getKeyList(String server, long start, long end) {
		// TODO Auto-generated method stub
		ShardedJedis shardedJedis=shardedJedisPool.getResource();
		List<String> result=new ArrayList<String>();
		List<AlgorithmModel> algorithmModels=new ArrayList<AlgorithmModel>();
		try{
			result= shardedJedis.lrange(server, start, end);
			shardedJedisPool.returnResource(shardedJedis);
		}catch(Exception e){
			log.error("getKeyList fail by shardedJedisPool,this reason",e);
			shardedJedisPool.returnBrokenResource(shardedJedis);
			if(readShardedJedisPool!=null){
				ShardedJedis readShardedJedis=readShardedJedisPool.getResource();
				try{
					result= readShardedJedis.lrange(server, start, end);
					readShardedJedisPool.returnResource(readShardedJedis);
					for(int i=0;i<result.size();i++){
						algorithmModels.add(maps.get(result.get(i)));
					}
				}catch(Exception ex){
					log.error("getKeyList fail by readShardedJedisPool ,this reason",e);
					readShardedJedisPool.returnBrokenResource(readShardedJedis);
				}
			}
			
		}
		return algorithmModels;
	}

	@Override
	public void delByKey(String key) {
		// TODO Auto-generated method stub
		ShardedJedis shardedJedis=shardedJedisPool.getResource();
		try{
			shardedJedis.del(key);
		}catch(Exception e){
			log.error("delByKey fail by shardedJedisPool,this reason",e);
			shardedJedisPool.returnBrokenResource(shardedJedis);
			if(readShardedJedisPool!=null){
				ShardedJedis readShardedJedis=shardedJedisPool.getResource();
				try{
					readShardedJedis.del(key);
					readShardedJedisPool.returnResource(readShardedJedis);
				}catch(Exception ex){
					log.error("delByKey fail by readShardedJedisPool ,this reason",e);
					readShardedJedisPool.returnBrokenResource(readShardedJedis);
				}
			}
			
		}
		shardedJedisPool.returnResource(shardedJedis);
	}

	@Override
	public AlgorithmModel getServer(String key) {
		// TODO Auto-generated method stub
		ShardedJedis shardedJedis=shardedJedisPool.getResource();
		String server=null;
		try{
			server=shardedJedis.get(key);
			shardedJedisPool.returnResource(shardedJedis);
		}catch(Exception e){
			log.error("getServer fail by shardedJedisPool ,this reason",e);
			shardedJedisPool.returnBrokenResource(shardedJedis);
			
			if(readShardedJedisPool!=null){
				ShardedJedis readShardedJedis=readShardedJedisPool.getResource();
				try{
					server=readShardedJedis.get(key);
					readShardedJedisPool.returnResource(readShardedJedis);
				}catch(Exception ex){
					log.error("getServer fail by readShardedJedisPool ,this reason",e);
					readShardedJedisPool.returnBrokenResource(readShardedJedis);
				}
			}
			
		}
		return maps.get(server);
	}

	/**
	 * @param readShardedJedisPool the readShardedJedisPool to set
	 */
	public void setReadShardedJedisPool(ShardedJedisPool readShardedJedisPool) {
		this.readShardedJedisPool = readShardedJedisPool;
	}
	
}
